﻿using HalconDotNet;
using IniReadWrite;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using VisionRoc.Tool;

namespace VisionRoc.Core
{
    public class ModelMatch
    {
        /// <summary>
        /// 模版参数完整路径
        /// </summary>
        public string ModelPath;

        /// <summary>
        /// 模版句柄路径
        /// </summary>
        string ModelIDPath;
        public ModelMatch(string _Path)
        {
            HOperatorSet.GenEmptyObj(out ModelRegion);
            HOperatorSet.GenEmptyObj(out SearchRegioin);
            HOperatorSet.GenEmptyObj(out ImageReduce);
            HOperatorSet.GenEmptyObj(out ShapeContours);
            HOperatorSet.GenEmptyObj(out ContoursAffine);
            HOperatorSet.GenEmptyObj(out Cross);
            HOperatorSet.GenEmptyObj(out domain);
            HOperatorSet.GenEmptyObj(out region);

            //判断文件路径是否存在
            if (!Directory.Exists(_Path))
            {
                Directory.CreateDirectory(_Path);
            }
            ModelPath = _Path + "\\Match.ini";
            //判断文件是否存在
            if (File.Exists(ModelPath))
            {
                ReadMatchParameter();
            }
            else
            {
                //如果文件不存在系统输入默认参数
                AngleStart = 0;
                AngleExtand = 360;
                MinScore = 0.5;
                NumMatches = 1;
                MaxOverlap = 0.5;
                NumLevels = 0;
                Greediness = 0.8;
                SubPixel = "least_squares";
            }

            ModelIDPath = _Path + "//ModelID.shm";
            //判断文件是否存在
            if (File.Exists(ModelIDPath))
            {
                ReadShapeModel();
            }
            else
            {

            }
        }

        /// <summary>
        /// 实时搜索框区域
        /// </summary>
        HObject SearchRegioin;

        HObject ImageReduce;

        /// <summary>
        /// 模板轮廓
        /// </summary>
        HObject ShapeContours;

        HObject domain; HObject region;

        /// <summary>
        /// 是否找到模版 1：OK 2：NG
        /// </summary>
        public int IsFindModel;

        #region 模版创建参数
        /// <summary>
        /// 创建模板参数 金字塔等级
        /// </summary>
        public HTuple Create_NumberLevel = new HTuple();

        /// <summary>
        /// 创建模板数  极性
        /// </summary>
        public HTuple Create_Metric = new HTuple();

        /// <summary>
        /// 创建模板参数 对比度
        /// </summary>
        public HTuple Create_Contranst = new HTuple();

        /// <summary>
        /// 创建模板参数 最小对比度
        /// </summary>
        public HTuple Create_MinContranst = new HTuple();

        /// <summary>
        /// 模板句柄
        /// </summary>
        public HTuple ModelID;

        /// <summary>
        /// 仿射后的轮廓
        /// </summary>
        HObject ContoursAffine;

        /// <summary>
        /// 轮廓仿射矩阵
        /// </summary>
        HTuple hom = new HTuple();

        /// <summary>
        /// 模板坐标十字叉
        /// </summary>
        HObject Cross;

        /// <summary>
        /// 模版创建区域
        /// </summary>
        public HObject ModelRegion;

        #endregion

        #region 模版查找参数

        [Category("1模板参数"), DisplayName("1.起始角度"), Description("角度起始：搜索时的起始角度"), Browsable(true), ReadOnly(false)]
        public double AngleStart { get; set; } = 0;

        [Category("1模板参数"), DisplayName("2.角度范围"), Description("角度范围：搜索时的角度范围"), Browsable(true), ReadOnly(false)]
        public double AngleExtand { get; set; } = 180;

        [Category("1模板参数"), DisplayName("3.最小分数"), Description("角度范围：查找模板分数"), Browsable(true), ReadOnly(false)]
        public double MinScore { get; set; } = 0.5;

        [Category("1模板参数"), DisplayName("4.匹配数量"), Description("最大匹配数量：定义要输出的匹配的最大个数"), Browsable(true), ReadOnly(false)]
        public int NumMatches { get; set; } = 1;

        [Category("1模板参数"), DisplayName("5.最大重叠比"), Description("最大重叠比：\r\n当找到的目标存在重叠时\r\n，且重叠大于该值时选择一个好的输出"), Browsable(true), ReadOnly(false)]
        public double MaxOverlap { get; set; } = 0.5;

        [Category("1模板参数"), DisplayName("6.金字塔等级"), Description("金字塔等级"), Browsable(true), ReadOnly(false)]
        public int NumLevels { get; set; } = 0;

        [Category("1模板参数"), DisplayName("7.贪婪指数"), Description("贪婪指数：搜索启发式，一般都设为0.9，越高速度快,容易出现找不到的情况"), Browsable(true), ReadOnly(false)]
        public double Greediness { get; set; } = 0.8;

        [Category("1模板参数"), DisplayName("8.亚像素"), Description("亚像素"), Browsable(true), ReadOnly(false)]
        public string SubPixel { get; set; }

        [Category("2显示参数"), DisplayName("1.显示轮廓"), Description("是否显示轮廓"), Browsable(true), ReadOnly(false)]
        public bool DisplayShape { get; set; } = false;

        [Category("2显示参数"), DisplayName("2.显示搜索区"), Description("是否显示搜索区"), Browsable(true), ReadOnly(false)]
        public bool DisplaySearch { get; set; } = false;

        [Category("2显示参数"), DisplayName("3.显示位置"), Description("是否显示位置"), Browsable(true), ReadOnly(false)]
        public bool DisplayLoction { get; set; } = false;

        [Category("2显示参数"), DisplayName("4.模版颜色"), Description("模版颜色"), Browsable(true), ReadOnly(false)]
        public string ShapeColor { get; set; } = "green";

        [Category("2显示参数"), DisplayName("5.搜索区域颜色"), Description("搜索区域颜色"), Browsable(true), ReadOnly(false)]
        public string SerachColor { get; set; } = "blue";

        [Category("2显示参数"), DisplayName("6.位置颜色"), Description("搜索区域颜色"), Browsable(true), ReadOnly(false)]
        public string CrossColor { get; set; } = "red";

        [Category("2显示参数"), DisplayName("7.位置大小"), Description("位置大小"), Browsable(true), ReadOnly(false)]
        public int LoctionSize { get; set; } = 5;

        [Category("2显示参数"), DisplayName("8.线宽"), Description("线宽"), Browsable(true), ReadOnly(false)]
        public int LineWidth { get; set; } = 5;

        #endregion

        #region 区域搜索框位置输出变量
        public double SearchRegionRow1, SearchRegionCol1, SearchRegionRow2, SearchRegionCol2;
        #endregion

        /// <summary>
        /// 查找模板输出参数
        /// </summary>
        public HTuple Row = new HTuple(), Col = new HTuple(), Angle = new HTuple(), Score = new HTuple();

        /// <summary>
        /// 创建模版时坐标
        /// </summary>
        public HTuple Create_Row = new HTuple(), Create_Col = new HTuple(), Create_Angle = new HTuple();

        public void Create_Shape_Model(HObject Image, HWindow hWindow)
        {
            try
            {
                double AngleS = MyHOperatorSet.DegToRad(-180);
                double AngleE = MyHOperatorSet.DegToRad(360);
                HOperatorSet.ReduceDomain(Image, ModelRegion, out HObject ImageReduced);
                HOperatorSet.CreateShapeModel(ImageReduced, Create_NumberLevel, AngleS, AngleE, "auto", "auto", Create_Metric, Create_Contranst, Create_MinContranst, out ModelID);
                // HOperatorSet.CreateShapeModel(ImageReduced, Create_NumberLevel, -(Math.PI / 2), Math.PI, "auto", "auto", Create_Metric, Create_Contranst, Create_MinContranst, out ModelID);
                if (ModelID.Length > 0)
                {
                    Find_Shape_Model(Image, hWindow, out HTuple hom);
                    if (Score.Length > 0)
                    {
                        Create_Row = Row;
                        Create_Col = Col;
                        Create_Angle = Angle;
                        IniAPI.INIWriteValue(ModelPath, "CreateTemplateLocation", "Row", Create_Row.ToString());
                        IniAPI.INIWriteValue(ModelPath, "CreateTemplateLocation", "Col", Create_Col.ToString());
                        IniAPI.INIWriteValue(ModelPath, "CreateTemplateLocation", "Angle", Create_Angle.ToString());
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
                TxtAPI.WriteLogTxt(Global.m_ImageSavePath.LogPath, "模版创建异常：" + ex.ToString());
            }
        }

        public bool Find_Shape_Model(HObject Image, HWindow hWindow, out HTuple HomMat2D)
        {
            IsFindModel = 0; // 状态复位
            HomMat2D = new HTuple();
            try
            {
                HOperatorSet.CountObj(Image, out HTuple tuple1);
                if (tuple1.I == 0)
                {
                    MyHOperatorSet.DispMeassge(hWindow, "图像为空！", "window", "center", "center", 20, "red");
                    return false;
                }
                if (ModelID.Length > 0)
                {
                    double AngleS = MyHOperatorSet.DegToRad(AngleStart);
                    double AngleE = MyHOperatorSet.DegToRad(AngleExtand);
                    //判断区域搜索还是全图搜索
                    if (SearchRegionRow1 > 0 && SearchRegionRow2 > 0)
                    {

                        SearchRegioin.Dispose();
                        HOperatorSet.GenRectangle1(out SearchRegioin, SearchRegionRow1, SearchRegionCol1, SearchRegionRow2, SearchRegionCol2);
                        //ImageReduce.Dispose();
                        //HOperatorSet.ReduceDomain(Image, SearchRegioin, out ImageReduce);
                        domain.Dispose();
                        HOperatorSet.GetDomain(Image, out domain);
                        HOperatorSet.Difference(domain, SearchRegioin, out region);
                        ImageReduce.Dispose();
                        HOperatorSet.PaintRegion(region, Image, out ImageReduce, 0, "fill");
                        HOperatorSet.FindShapeModel(ImageReduce, ModelID, AngleS, AngleE, MinScore, NumMatches, MaxOverlap, SubPixel, NumLevels, Greediness, out Row, out Col, out Angle, out Score);
                    }
                    else
                    {
                        Row.Dispose(); Col.Dispose(); Angle.Dispose(); Score.Dispose();
                        HOperatorSet.FindShapeModel(Image, ModelID, AngleS, AngleE, MinScore, NumMatches, MaxOverlap, SubPixel, NumLevels, Greediness, out Row, out Col, out Angle, out Score);
                    }
                    // 判断是否查找到模板
                    if (Score.Length > 0)
                    {

                        HOperatorSet.SetLineWidth(hWindow, LineWidth);
                        //判断是否显示轮廓
                        if (DisplayShape)
                        {
                            HOperatorSet.SetColor(hWindow, ShapeColor);
                            ShapeContours.Dispose();
                            HOperatorSet.GetShapeModelContours(out ShapeContours, ModelID, 1);
                            for (int i = 0; i < Score.Length; i++)
                            {
                                hom.Dispose();
                                HOperatorSet.VectorAngleToRigid(0, 0, 0, Row[i], Col[i], Angle[i], out hom);
                                ContoursAffine.Dispose();
                                HOperatorSet.AffineTransContourXld(ShapeContours, out ContoursAffine, hom);
                                HOperatorSet.DispObj(ContoursAffine, hWindow);
                            }
                        }
                        // 判断是否显示位置坐标
                        if (DisplayLoction)
                        {
                            for (int i = 0; i < Score.Length; i++)
                            {
                                Cross.Dispose();
                                HOperatorSet.GenCrossContourXld(out Cross, Row[i], Col[i], LoctionSize, Angle[i]);
                                HOperatorSet.SetColor(hWindow, CrossColor);
                                HOperatorSet.DispObj(Cross, hWindow);
                            }
                        }
                        //判断是否显示搜索区域
                        if (DisplaySearch)
                        {
                            // 判断区域坐标是否有值
                            if (SearchRegionRow1 > 0 && SearchRegionRow2 > 0)
                            {
                                MyHOperatorSet.DispContour(hWindow, Model.margin, SerachColor, SearchRegioin);
                            }
                        }
                        //恢复默认系统设置
                        HOperatorSet.SetColored(hWindow, 12);
                        HOperatorSet.SetLineWidth(hWindow, 2);
                        HOperatorSet.SetColor(hWindow, "red");
                        HomMat2D.Dispose();
                        HOperatorSet.VectorAngleToRigid(Create_Row, Create_Col, Create_Angle, Row, Col, Angle, out HomMat2D);
                        IsFindModel = 1;
                        return true;
                    }
                    else
                    {
                        IsFindModel = 2;
                        MyHOperatorSet.DispMeassge(hWindow, "未找到模版", "window", "center", "center", 20, "red");
                        return false;
                    }
                }
                else
                {
                    MyHOperatorSet.DispMeassge(hWindow, "ModelID为空", "window", "center", "center", 20, "red");
                    return false;
                }
            }
            catch
            {
                IsFindModel = 2;
                MyHOperatorSet.DispMeassge(hWindow, "查找模版异常", "window", "center", "center", 20, "red");
                return false;
            }
        }

        /// <summary>
        /// 保存模板参数
        /// </summary>
        public void WriteMatchParameter()
        {
            IniAPI.INIWriteValue(ModelPath, "FindTemplateParameter", "AngleStart", AngleStart.ToString());
            IniAPI.INIWriteValue(ModelPath, "FindTemplateParameter", "AngleExtand", AngleExtand.ToString());
            IniAPI.INIWriteValue(ModelPath, "FindTemplateParameter", "MinScore", MinScore.ToString());
            IniAPI.INIWriteValue(ModelPath, "FindTemplateParameter", "NumMatches", NumMatches.ToString());
            IniAPI.INIWriteValue(ModelPath, "FindTemplateParameter", "MaxOverlap", MaxOverlap.ToString());
            IniAPI.INIWriteValue(ModelPath, "FindTemplateParameter", "NumLevels", NumLevels.ToString());
            IniAPI.INIWriteValue(ModelPath, "FindTemplateParameter", "Greediness", Greediness.ToString());
            IniAPI.INIWriteValue(ModelPath, "FindTemplateParameter", "SubPixel", SubPixel.ToString());

            IniAPI.INIWriteValue(ModelPath, "SearchRegionParameter", "SearchRegionRow1", SearchRegionRow1.ToString());
            IniAPI.INIWriteValue(ModelPath, "SearchRegionParameter", "SearchRegionCol1", SearchRegionCol1.ToString());
            IniAPI.INIWriteValue(ModelPath, "SearchRegionParameter", "SearchRegionRow2", SearchRegionRow2.ToString());
            IniAPI.INIWriteValue(ModelPath, "SearchRegionParameter", "SearchRegionCol2", SearchRegionCol2.ToString());

            IniAPI.INIWriteValue(ModelPath, "CreateTemplateParameter", "NumberLevel", Create_NumberLevel.ToString());
            IniAPI.INIWriteValue(ModelPath, "CreateTemplateParameter", "Metric", Create_Metric.ToString());
            IniAPI.INIWriteValue(ModelPath, "CreateTemplateParameter", "Contranst", Create_Contranst.ToString());
            IniAPI.INIWriteValue(ModelPath, "CreateTemplateParameter", "MinContranst", Create_MinContranst.ToString());

            IniAPI.INIWriteValue(ModelPath, "DisplaySet", "DisplayLoction", DisplayLoction.ToString());
            IniAPI.INIWriteValue(ModelPath, "DisplaySet", "DisplayShape", DisplayShape.ToString());
            IniAPI.INIWriteValue(ModelPath, "DisplaySet", "DisplaySearch", DisplaySearch.ToString());


            IniAPI.INIWriteValue(ModelPath, "DisplaySet", "LoctionSize", LoctionSize.ToString());
            IniAPI.INIWriteValue(ModelPath, "DisplaySet", "LineWidth", LineWidth.ToString());
            IniAPI.INIWriteValue(ModelPath, "DisplaySet", "ShapeColor", ShapeColor.ToString());
            IniAPI.INIWriteValue(ModelPath, "DisplaySet", "CrossColor", CrossColor.ToString());
            IniAPI.INIWriteValue(ModelPath, "DisplaySet", "SerachColor", SerachColor.ToString());
        }

        /// <summary>
        /// 读取模板参数
        /// </summary>
        public void ReadMatchParameter()
        {
            try
            {
                AngleStart = Convert.ToDouble(IniAPI.INIGetStringValue(ModelPath, "FindTemplateParameter", "AngleStart", "0"));
                AngleExtand = Convert.ToDouble(IniAPI.INIGetStringValue(ModelPath, "FindTemplateParameter", "AngleExtand", "360"));
                MinScore = Convert.ToDouble(IniAPI.INIGetStringValue(ModelPath, "FindTemplateParameter", "MinScore", "0.5"));
                NumMatches = Convert.ToInt32(IniAPI.INIGetStringValue(ModelPath, "FindTemplateParameter", "NumMatches", "1"));

                MaxOverlap = Convert.ToDouble(IniAPI.INIGetStringValue(ModelPath, "FindTemplateParameter", "MaxOverlap", "0.5"));
                NumLevels = Convert.ToInt32(IniAPI.INIGetStringValue(ModelPath, "FindTemplateParameter", "NumLevels", "0"));
                Greediness = Convert.ToDouble(IniAPI.INIGetStringValue(ModelPath, "FindTemplateParameter", "Greediness", "0.5"));
                SubPixel = IniAPI.INIGetStringValue(ModelPath, "FindTemplateParameter", "SubPixel", "least_squares");

                SearchRegionRow1 = Convert.ToDouble(IniAPI.INIGetStringValue(ModelPath, "SearchRegionParameter", "SearchRegionRow1", "0"));
                SearchRegionCol1 = Convert.ToDouble(IniAPI.INIGetStringValue(ModelPath, "SearchRegionParameter", "SearchRegionCol1", "0"));
                SearchRegionRow2 = Convert.ToDouble(IniAPI.INIGetStringValue(ModelPath, "SearchRegionParameter", "SearchRegionRow2", "0"));
                SearchRegionCol2 = Convert.ToDouble(IniAPI.INIGetStringValue(ModelPath, "SearchRegionParameter", "SearchRegionCol2", "0"));

                Create_NumberLevel = IniAPI.INIGetStringValue(ModelPath, "CreateTemplateParameter", "NumberLevel", "0");
                Create_Metric = IniAPI.INIGetStringValue(ModelPath, "CreateTemplateParameter", "Metric", "use_polarity");
                Create_Contranst = IniAPI.INIGetStringValue(ModelPath, "CreateTemplateParameter", "Contranst", "auto");
                Create_MinContranst = IniAPI.INIGetStringValue(ModelPath, "CreateTemplateParameter", "MinContranst", "auto");

                DisplayLoction = Convert.ToBoolean(IniAPI.INIGetStringValue(ModelPath, "DisplaySet", "DisplayLoction", "0"));
                DisplayShape = Convert.ToBoolean(IniAPI.INIGetStringValue(ModelPath, "DisplaySet", "DisplayShape", "0"));
                DisplaySearch = Convert.ToBoolean(IniAPI.INIGetStringValue(ModelPath, "DisplaySet", "DisplaySearch", "0"));

                LoctionSize = Convert.ToInt32(IniAPI.INIGetStringValue(ModelPath, "DisplaySet", "LoctionSize", "20"));
                LineWidth = Convert.ToInt32(IniAPI.INIGetStringValue(ModelPath, "DisplaySet", "LineWidth", "3"));
                ShapeColor = IniAPI.INIGetStringValue(ModelPath, "DisplaySet", "ShapeColor", "green");
                CrossColor = IniAPI.INIGetStringValue(ModelPath, "DisplaySet", "CrossColor", "red");
                SerachColor = IniAPI.INIGetStringValue(ModelPath, "DisplaySet", "SerachColor", "blue");

                Create_Row = Convert.ToDouble(IniAPI.INIGetStringValue(ModelPath, "CreateTemplateLocation", "Row", "0"));
                Create_Col = Convert.ToDouble(IniAPI.INIGetStringValue(ModelPath, "CreateTemplateLocation", "Col", "0"));
                Create_Angle = Convert.ToDouble(IniAPI.INIGetStringValue(ModelPath, "CreateTemplateLocation", "Angle", "0"));
            }
            catch { }

        }

        /// <summary>
        /// 保存模板
        /// </summary>
        public bool WriteShapelModel()
        {
            HOperatorSet.WriteShapeModel(ModelID, ModelIDPath);
            if (File.Exists(ModelIDPath))
            {
                //判断如果有这个文件则保存成功
                return true;
            }
            return false;
        }

        /// <summary>
        /// 读取模板 
        /// </summary>
        public bool ReadShapeModel()
        {
            if (File.Exists(ModelPath))
            {
                //判断如果有模板句柄这个文件 就读取
                HOperatorSet.ReadShapeModel(ModelIDPath, out ModelID);
                if (ModelID.Length > 0)
                {
                    return true;
                }
                return false;
            }
            return false;
        }


    }

    class GenderItem : StringConverter
    {
        ////true 启用,false 禁用
        public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
        {
            return true;
        }

        public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
        {
            return new StandardValuesCollection(new string[] { "none", "interpolation", "least_squares", "least_squares_high", "least_squares_very_high" }); //编辑下拉框中的items
        }

        //true：禁用文本编辑，false：启用文本编辑
        public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
        {
            return true;
        }
    }
}
